/*
 *  Filename:lsv_volume_gc.h
 *  Description:
 *
 *  Created on: 2017年3月13日
 *  Author: Asdf(825674301)
 */

#ifndef _LSV_VOLUME_GC_H_
#define _LSV_VOLUME_GC_H_

/**
 * @file Volume GC模块简介
 *
 * Volume GC模块管理底层物理存储空间，如lich卷，或文件
 *
 * 通过bitmap来管理全部的存储空间，每个chunk用2bit来表示：存储类型+是否已分配。
 *
 * 通过avachk_list (available chunk)等结构来管理分配和回收过程，按存储类型分别组织
 *
 * avachk_list分内存和磁盘两部分，内存按循环链表组织，磁盘按stack组织。
 * - 当内存没有可用chunk时，从磁盘加载；或者扩展卷尾部
 * - 当free导致内存满时，按stack方式置换到磁盘上。
 *
 * 重启有两种情况：
 * - flush/load：正常情况下的关闭/启动
 * - 异常情况下，恢复过程是根据bitmap重建avachk_list
 */

#include "lsv_conf.h"
#include "lsv_types.h"
#include "lsv_volume_proto.h"

#define LSV_VOLGC_RECORD_AVACHK_NUM               ((LSV_CHUNK_SIZE-sizeof(lsv_u32_t)*2)/sizeof(lsv_u32_t))

#define LSV_VOLGC_STORAGE_BIT_LEN                 (2)
#define LSV_VOLGC_BYTE_RECORD_NUM                 (8/LSV_VOLGC_STORAGE_BIT_LEN)
#define LSV_VOLGC_CHUNK_RECORD_NUM                (LSV_CHUNK_SIZE*8/LSV_VOLGC_STORAGE_BIT_LEN)

// 每chunk 2bit，所需字节数, 64MB
#define LSV_VOLGC_STORAGE_BITMAP_NUM              (LSV_MAX_CHUNK_NUM*LSV_VOLGC_STORAGE_BIT_LEN/8)
#define LSV_VOLGC_STORAGE_CHUNK_NUM               (LSV_MAX_CHUNK_NUM*LSV_VOLGC_STORAGE_BIT_LEN/8/LSV_CHUNK_SIZE)

#define LSV_VOLGC_STORAGE_SET_BASE                (LSV_PRIM_CHUNK_NUM)

// #define LSV_VOLGC_STORAGE_SET_SIZE                (LSV_PAGE_SIZE)

// 每页用一位，所需字节数, 2KB
#define LSV_VOLGC_STORAGE_BITMAP_DIRTY_BITMAP_NUM (LSV_VOLGC_STORAGE_BITMAP_NUM/LSV_PAGE_SIZE/8)

// 从这里开始分配，之前的chunk，用途由系统规则内定
#define LSV_VOLGC_TAIL_INIT                       (LSV_PRIM_CHUNK_NUM + LSV_VOLGC_STORAGE_CHUNK_NUM)

/*===define volgc storage in prim chunk page===*/

/*size*/
#define LSV_VOLGC_TAIL_AREA (sizeof(lsv_u32_t))

/*===end volgc storage in prim chunk page===*/

#pragma pack(8)

/**
 * chunk0上的volume元数据
 */
typedef struct {
        uint32_t tail;
        uint32_t next_chkids[LSV_STORAGE_TYPE_COUNT];
} lsv_volume_meta_t;

/**
 * free list的内存和磁盘布局, single linked list
 */
typedef struct __lsv_volgc_avachk_record {
        lsv_u32_t count;
        lsv_u32_t next_chkid;
        lsv_u32_t avail_chkid[LSV_VOLGC_RECORD_AVACHK_NUM];
} lsv_volgc_avachk_record_t;

#pragma pack()

typedef struct __lsv_volgc_avachk_list {
        lsv_lock_t lock;

        // disk structure, malloc dynamically
        // 指向底层卷的第一个chunk，单链表
        // 组织成stack形式
        lsv_u32_t next_chkid;

        // memory structure, circular queue
        // malloc位置
        lsv_u32_t malloc_record;
        // free位置，无空间时，压栈到磁盘, 磁盘上的chunk按stack组织
        // 磁盘和内存，采用统一的数据存储结构
        lsv_u32_t free_record;

        lsv_volgc_avachk_record_t record[LSV_VOLGC_AVACHK_LIST_NUM];

        // stat
        uint64_t malloc_count;
        uint64_t free_count;
} lsv_volgc_avachk_list_t;

/**
 * 每个存储类型维护自己的空闲chunk列表，分配的基本单元是512.
 */
typedef struct __lsv_volgc_info {
        // low-level volume tail
        lsv_u32_t tail;
        lsv_lock_t tail_lock;

        // each STORAGE_TYPE a list
        lsv_volgc_avachk_list_t avachk_list[LSV_STORAGE_TYPE_COUNT];

        // 256T/1M/8 * 2 = 64M
        lsv_u8_t bitmaps[LSV_VOLGC_STORAGE_BITMAP_NUM];

        // 64M/4K/8 = 2K
        lsv_u8_t dirty_page_bitmap[LSV_VOLGC_STORAGE_BITMAP_DIRTY_BITMAP_NUM];
} lsv_volgc_info_t;

int lsv_volume_volgc_create(lsv_volume_proto_t *lsv_info);

int lsv_volume_volgc_delete(lsv_volume_proto_t *lsv_info);

/**
 * @brief 持久化avachk_list(memory）.
 *
 * @param lsv_info
 * @return
 */
int lsv_volume_volgc_flush(lsv_volume_proto_t *lsv_info);

int lsv_volume_volgc_load(lsv_volume_proto_t *lsv_info);

/**
 * @brief 根据bitmap重建avachk_list(memory+disk）.
 *
 * @param lsv_info
 * @return
 */
int lsv_volume_volgc_recovery(lsv_volume_proto_t *lsv_info);

/**
 *
 * @pre
 * @post
 *
 * @param lsv_info
 * @param type
 * @param chunk_id
 * @return
 */
int lsv_volume_volgc_malloc(lsv_volume_proto_t *lsv_info, lsv_u8_t type, lsv_u32_t *chunk_id);

int lsv_volume_volgc_free(lsv_volume_proto_t *lsv_info, lsv_u8_t type, lsv_u32_t chunk_id);

int lsv_volume_volgc_malloc_batch(lsv_volume_proto_t *lsv_info, lsv_u8_t type, lsv_u32_t count, lsv_u32_t *chunk_id);

int lsv_volume_volgc_free_batch(lsv_volume_proto_t *lsv_info, lsv_u8_t type, lsv_u32_t count, lsv_u32_t *chunk_id);

int lsv_volume_gc_stat(lsv_volume_proto_t *lsv_info, const char *func, int line);

// -- internals

// void __lsv_volume_bitmap_set_dirty(lsv_u8_t *storage_bitmap_dirty_bitmap, lsv_u32_t chunk_id);
// void __lsv_volume_bitmap_unset_dirty(lsv_u8_t *storage_bitmap_dirty_bitmap, lsv_u32_t idx) ;
// lsv_u8_t __lsv_volume_bitmap_get_dirty(lsv_u8_t *storage_bitmap_dirty_bitmap, lsv_u32_t idx);

int lsv_volume_bitmap_malloc(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, lsv_u8_t type);

int lsv_volume_bitmap_free(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, lsv_u8_t type);

int lsv_volume_bitmap_batch_set(lsv_volume_proto_t *lsv_info, lsv_u32_t count, lsv_u32_t *chunk_id);

#endif /* _LSV_VOLUME_GC_H_ */
